#include "computeserver.hh"

ComputeServer::ComputeServer()
{
    _run = false;
    _network = Socket(Socket::TCP4, "127.0.0.1", 4242);
}

ComputeServer::ComputeServer(string address, int port)
{
    _run = false;
    _network = Socket(Socket::TCP4, address, port);
}

void ComputeServer::Start()
{
    cout << "Compute Server starting..." << endl;
    setRunning(true);
    if (!(init() && createThread(&compute_server_starter, (void*)this)))
        cerr << "Compute Server cannot create main thread!" << endl;
    cout << "Compute Server started..." << endl;
}

void ComputeServer::Stop()
{
    setRunning(false);
    cout << "Compute Server stopping..." << endl;
    if (false == joinThread())
        destroyThread();
    cout << "Compute Server stopped" << endl;
}

void ComputeServer::loop()
{
    list<ClientInstance*>::iterator it;
    Socket *clientSocket;
    ClientInstance *newClient;
    bool found;

    while (isRunning())
    {
        if (0 != (clientSocket = _network.accept())) // Get new clients
        {
            newClient = new ClientInstance(clientSocket, &_counter);
            newClient->Start();
            _clients.push_front(newClient);
        }

        found = true;
        while (found) // Delete dead clients
        {
            found = false;
            for (it = _clients.begin(); it != _clients.end(); ++it)
            {
                if (false == (*it)->IsRunning())
                {
                    (*it)->Stop();
                    _clients.erase(it);
                    found = true;
                    break;
                }
            }
        }
    }

    found = true;
    while (found) // Delete all remaining clients
    {
        found = false;
        for (it = _clients.begin(); it != _clients.end(); ++it)
        {
            (*it)->Stop();
            _clients.erase(it);
            found = true;
            break;
        }
    }
    _clients.clear();
}

bool ComputeServer::init()
{
    _network.bind();
    _network.listen();

    return (true);
}

bool ComputeServer::isRunning()
{
    bool tmp;

    lock();
    tmp = _run;
    unlock();
    return (tmp);
}

void ComputeServer::setRunning(bool run)
{
    lock();
    _run = run;
    unlock();
}

void *compute_server_starter(void *data)
{
    ComputeServer *classInstance = reinterpret_cast<ComputeServer*>(data);
    classInstance->loop();
    return (data);
}
